// 手写防抖函数：
// 就是指触发事件后在 n 秒内函数只能执行一次(且是最后一次)，如果在 n 秒内又触发了事件，则会重新计算函数执行时间
// 核心是利用 `setTimeout`定时器来实现：
// 1. 声明定时器变量
// 2. 每次鼠标移动(事件触发)的时候都要先判断是否有定时器,如果有先清除以前的定时器
// 3. 如果没有定时器,则开启定时器,存入到定时器变量里面
// 4. 定时器里面写函数调用

// 应用场景
// 搜索框输入提示：在搜索框输入内容时，使用防抖，只有在用户停止输入一段时间后才会发起搜索请求，减少了请求次数，提高了性能。
// 窗口大小改变：当窗口大小改变时，会触发 resize 事件。使用防抖可以确保只有在用户停止调整窗口大小一段时间后才进行布局计算。

function debounce(func, delay) {
  let timer = null;
  return function () {
    // 在 debounce 函数返回的新函数里，this 指向的是调用这个新函数的对象
    const context = this;
    // arguments 包含了调用这个新函数时传递的所有参数
    const args = arguments;
    console.log(this)  // obj  

    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      func.apply(context, args);
    }, delay);
  };
}

const obj = {
  name: 'John',
  sayName: function () {
    console.log(`My name is ${this.name}`);
  }
};

const debouncedSayName = debounce(obj.sayName, 1000);
// 调用防抖函数
debouncedSayName.call(obj);


// 手写节流函数：
// 是指连续触发事件但是在 n 秒中**只执行一次（且是第一次）**函数
// 节流的核心就是利用定时器(`setTimeout`)来实现：
// 1.声明一个定时器变量
// 2.当鼠标每次滑动都先判断是否有定时器了,如果有定时器则不开启新定时器
// 3.如果没有定时器则开启定时器,记得存到变量里面
//    3.1定时器里面调用执行的函数
//    3.2定时器里面要把定时器清空

// 应用场景
// 滚动加载：在网页滚动加载更多内容时，使用节流可以确保在一定时间内只触发一次加载事件，避免过度加载，影响性能。
// 按钮点击：对于一些需要避免用户频繁点击的按钮，如提交表单按钮、点赞按钮等，使用节流可以限制按钮点击的频率，防止用户在短时间内多次点击造成不必要的操作。
function throttle(func, delay) {
  let timer = null;
  return function () {
    if (!timer) {
      // 保存当前函数的上下文和参数
      const context = this;
      const args = arguments;
      // 立即执行函数
      func.apply(context, args);
      // 设置定时器
      timer = setTimeout(() => {
        // 定时器到期后，将 timer 置为 null，以便下次可以再次执行函数
        timer = null;
      }, delay);
    }
  };
}

// 示例函数，用于测试节流效果
function showMessage(message) {
  console.log(message);
}

// 创建节流后的函数，时间间隔为 2000 毫秒（即 2 秒）
const throttledShowMessage = throttle(showMessage, 2000);

// 模拟频繁调用
for (let i = 0; i < 5; i++) {
  throttledShowMessage(`Message ${i}`);
}
